package com.ctvit.cch.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.ctvit.cch.core.enums.GenerateStatusEnum;
import com.ctvit.cch.core.mapper.CreativeScriptDesignMapper;
import com.ctvit.cch.core.mapper.CreativeScriptSceneMapper;
import com.ctvit.cch.core.mapper.CreativeTopicMapper;
import com.ctvit.cch.core.pojo.domain.CreativeScriptDesign;
import com.ctvit.cch.core.pojo.domain.CreativeScriptScene;
import com.ctvit.cch.core.pojo.domain.CreativeTopic;
import com.ctvit.cch.core.pojo.dto.creative.CreativeScriptDesignGenerateDTO;
import com.ctvit.cch.core.pojo.dto.creative.CreativeScriptDesignRegenerateDTO;
import com.ctvit.cch.core.pojo.vo.creative.CreativeScriptDesignGetVO;
import com.ctvit.cch.core.pojo.vo.creative.CreativeScriptDesignListVO;
import com.ctvit.cch.core.pojo.vo.creative.CreativeScriptSceneListVO;
import com.ctvit.cch.core.service.ICreativeScriptDesignService;
import com.ruoyi.common.utils.SecurityUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

/**
 * 脚本设计Service业务层处理
 *
 * @author heyingcheng
 * @date 2025/10/11
 */
@Service
public class CreativeScriptDesignServiceImpl extends ServiceImpl<CreativeScriptDesignMapper, CreativeScriptDesign>
        implements ICreativeScriptDesignService {

    private final CreativeTopicMapper creativeTopicMapper;

    private final CreativeScriptSceneMapper creativeScriptSceneMapper;

    public CreativeScriptDesignServiceImpl(CreativeTopicMapper creativeTopicMapper,
            CreativeScriptSceneMapper creativeScriptSceneMapper) {
        this.creativeTopicMapper = creativeTopicMapper;
        this.creativeScriptSceneMapper = creativeScriptSceneMapper;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean generate(CreativeScriptDesignGenerateDTO dto) {
        CreativeTopic topic = creativeTopicMapper.selectById(dto.getTopicId());
        Assert.notNull(topic, "选题不存在");
        Assert.isTrue(GenerateStatusEnum.WAIT.name().equals(topic.getScriptStatus())
                || GenerateStatusEnum.FAILURE.name().equals(topic.getScriptStatus())
                || GenerateStatusEnum.SUCCESS.name().equals(topic.getScriptStatus()), "脚本设计已进行中");

        Long userId = SecurityUtils.getUserId();

        // 创建脚本设计对象
        CreativeScriptDesign scriptDesign = new CreativeScriptDesign();
        BeanUtils.copyProperties(dto, scriptDesign);

        scriptDesign.setScriptId(IdWorker.getIdStr());
        scriptDesign.setGenerateStatus(GenerateStatusEnum.QUEUED.name());

        boolean result = save(scriptDesign);
        Assert.isTrue(result, "保存脚本设计信息失败");

        // 更新关联的选题的生成脚本状态为等待
        result = SqlHelper.retBool(creativeTopicMapper.update(new LambdaUpdateWrapper<CreativeTopic>()
                .eq(CreativeTopic::getTopicId, dto.getTopicId())
                .eq(CreativeTopic::getSubmitterId, userId)
                .in(CreativeTopic::getScriptStatus,
                        Arrays.asList(GenerateStatusEnum.WAIT.name(), GenerateStatusEnum.FAILURE.name()))
                .set(CreativeTopic::getScriptStatus, GenerateStatusEnum.QUEUED.name())
                .set(CreativeTopic::getScriptTime, LocalDateTime.now())
                .set(CreativeTopic::getScriptId, scriptDesign.getScriptId())));
        Assert.isTrue(result, "选题脚本设计状态更新失败");

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean regenerate(CreativeScriptDesignRegenerateDTO dto) {
        CreativeScriptDesign cScriptDesign = getById(dto.getScriptId());
        Assert.notNull(cScriptDesign, "脚本设计不存在");
        Assert.isTrue(GenerateStatusEnum.WAIT.name().equals(cScriptDesign.getGenerateStatus())
                || GenerateStatusEnum.FAILURE.name().equals(cScriptDesign.getGenerateStatus())
                || GenerateStatusEnum.SUCCESS.name().equals(cScriptDesign.getGenerateStatus()), "脚本设计已进行中");
        cScriptDesign.setScriptId(null);

        CreativeScriptDesignGenerateDTO cScriptDesignGenerateDTO = new CreativeScriptDesignGenerateDTO();
        BeanUtils.copyProperties(cScriptDesign, cScriptDesignGenerateDTO);
        cScriptDesignGenerateDTO.setAdditionalContent(dto.getAdditionalContent());

        return generate(cScriptDesignGenerateDTO);
    }

    private CreativeScriptDesignGetVO assignCreativeScriptDesign(CreativeScriptDesign csdOne) {
        CreativeScriptDesignGetVO vo = new CreativeScriptDesignGetVO();
        BeanUtils.copyProperties(Objects.requireNonNull(csdOne), vo);

        if (GenerateStatusEnum.SUCCESS.name().equals(csdOne.getGenerateStatus())) {
            List<CreativeScriptScene> scriptSceneList = creativeScriptSceneMapper.selectList(
                    new LambdaQueryWrapper<CreativeScriptScene>()
                            .eq(CreativeScriptScene::getScriptId, csdOne.getScriptId())
                            .orderByAsc(CreativeScriptScene::getSceneIndex));

            List<CreativeScriptSceneListVO> scriptScenes = scriptSceneList.stream().map(item -> {
                CreativeScriptSceneListVO csslVo = new CreativeScriptSceneListVO();
                BeanUtils.copyProperties(Objects.requireNonNull(item), csslVo);
                return csslVo;
            }).collect(Collectors.toList());
            vo.setScenes(scriptScenes);
        }

        return vo;
    }

    @Override
    public CreativeScriptDesignGetVO get(String id) {
        CreativeScriptDesign one = getById(id);
        Assert.notNull(one, "脚本设计不存在");

        return assignCreativeScriptDesign(one);
    }

    @Override
    public CreativeScriptDesignGetVO getByTopicId(String topicId) {
        LambdaQueryWrapper<CreativeScriptDesign> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CreativeScriptDesign::getTopicId, topicId);
        queryWrapper.orderByDesc(CreativeScriptDesign::getUpdateTime);
        queryWrapper.last("LIMIT 1");

        CreativeScriptDesign one = getOne(queryWrapper);
        Assert.notNull(one, "脚本设计不存在");

        return assignCreativeScriptDesign(one);
    }

    @Override
    public List<CreativeScriptDesignListVO> listByGenerateStatus(String status) {
        // 使用 LambdaQueryWrapper 构造查询条件
        LambdaQueryWrapper<CreativeScriptDesign> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(CreativeScriptDesign::getGenerateStatus, status);
        queryWrapper.orderByDesc(CreativeScriptDesign::getUpdateTime);
        queryWrapper.last("LIMIT 10");

        // 执行查询
        List<CreativeScriptDesign> list = list(queryWrapper);

        // 转换为 VO 对象
        return list.stream().map(item -> {
            CreativeScriptDesignListVO vo = new CreativeScriptDesignListVO();
            BeanUtils.copyProperties(Objects.requireNonNull(item), vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<CreativeScriptDesignListVO> listByShotStatus(String status) {
        // 使用 LambdaQueryWrapper 构造查询条件
        LambdaQueryWrapper<CreativeScriptDesign> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(CreativeScriptDesign::getShotStatus, status);
        queryWrapper.orderByAsc(CreativeScriptDesign::getUpdateTime);
        queryWrapper.last("LIMIT 10");

        // 执行查询
        List<CreativeScriptDesign> list = list(queryWrapper);

        // 转换为 VO 对象
        return list.stream().map(item -> {
            CreativeScriptDesignListVO vo = new CreativeScriptDesignListVO();
            BeanUtils.copyProperties(Objects.requireNonNull(item), vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateGenerateStatus(String scriptId, String currentStatus, String targetStatus) {
        LambdaUpdateWrapper<CreativeScriptDesign> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CreativeScriptDesign::getScriptId, scriptId);
        updateWrapper.eq(CreativeScriptDesign::getGenerateStatus, currentStatus);
        updateWrapper.set(CreativeScriptDesign::getGenerateStatus, targetStatus);
        boolean result = update(updateWrapper);
        Assert.isTrue(result, "脚本设计状态更新失败");

        result = SqlHelper.retBool(creativeTopicMapper.update(new LambdaUpdateWrapper<CreativeTopic>()
                .eq(CreativeTopic::getScriptId, scriptId)
                .eq(CreativeTopic::getScriptStatus, currentStatus)
                .set(CreativeTopic::getScriptStatus, targetStatus)));
        Assert.isTrue(result, "选题脚本设计状态更新失败");

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateGenerateStatus(String scriptId, String topicId, String status,
            List<CreativeScriptScene> records) {
        LambdaUpdateWrapper<CreativeScriptDesign> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CreativeScriptDesign::getScriptId, scriptId);
        updateWrapper.set(CreativeScriptDesign::getGenerateStatus, status);
        boolean result = update(updateWrapper);
        Assert.isTrue(result, "脚本设计状态更新失败");

        result = SqlHelper.retBool(creativeTopicMapper.update(new LambdaUpdateWrapper<CreativeTopic>()
                .eq(CreativeTopic::getTopicId, topicId)
                .set(CreativeTopic::getScriptStatus, status)
                .set(CreativeTopic::getScriptTime, LocalDateTime.now())));
        Assert.isTrue(result, "选题脚本设计状态更新失败");

        for (CreativeScriptScene record : records) {
            record.setScriptId(scriptId);
            creativeScriptSceneMapper.insert(record);
        }

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateShotStatus(String topicId, String scriptId, String status) {
        boolean result = update(new LambdaUpdateWrapper<CreativeScriptDesign>()
                .eq(CreativeScriptDesign::getScriptId, scriptId)
                .set(CreativeScriptDesign::getShotStatus, status));
        Assert.isTrue(result, "脚本分镜设计状态更新失败");

        result = SqlHelper.retBool(creativeTopicMapper.update(new LambdaUpdateWrapper<CreativeTopic>()
                .eq(CreativeTopic::getTopicId, topicId)
                .set(CreativeTopic::getShotStatus, status)
                .set(CreativeTopic::getShotTime, LocalDateTime.now())));
        Assert.isTrue(result, "选题分镜设计状态更新失败");

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean completeShotDesign(String topicId, String scriptId) {
        List<CreativeScriptScene> scriptSceneList = creativeScriptSceneMapper
                .selectList(new LambdaQueryWrapper<CreativeScriptScene>()
                        .select(CreativeScriptScene::getSceneId, CreativeScriptScene::getShotStatus));

        Map<String, List<String>> statusToSceneIdsMap = scriptSceneList.stream()
                .collect(Collectors.groupingBy(
                        CreativeScriptScene::getShotStatus,
                        Collectors.mapping(CreativeScriptScene::getSceneId, Collectors.toList())));

        if (statusToSceneIdsMap.keySet().contains(GenerateStatusEnum.ING.name())
                || statusToSceneIdsMap.keySet().contains(GenerateStatusEnum.QUEUED.name())) {
            return updateShotStatus(topicId, scriptId, GenerateStatusEnum.QUEUED.name());
        }

        if (statusToSceneIdsMap.keySet().contains(GenerateStatusEnum.FAILURE.name())) {
            return updateShotStatus(topicId, scriptId, GenerateStatusEnum.FAILURE.name());
        }

        if (statusToSceneIdsMap.keySet().contains(GenerateStatusEnum.SUCCESS.name())
                && statusToSceneIdsMap.keySet().size() == 1) {
            return updateShotStatus(topicId, scriptId, GenerateStatusEnum.SUCCESS.name());
        }

        return false;
    }

}